package com.lingshu.customview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 自定义View
 */
public class CustomImageView extends View {
    //图片矩阵
    Matrix imageMatrix = new Matrix();

    //转换矩阵
    Matrix inverseMatrix = new Matrix();

    //数组
    float[] matrixValues = new float[9];
    float[] lineValues = new float[4];

    //线条列表
    List<LineItem> itemList = new ArrayList<>();

    //线条画笔
    Paint linePaint = new Paint();

    //文本画笔
    Paint textPaint = new Paint();

    //是否可以绘制
    public boolean canDrawStart = false;
    public boolean canDrawEnd = false;

    static final float CURSOR_RADIUS = 5;
    static final float OFFSET_Y = 200F;
    static final float OFFSET_X = 200F;

    //是否向左偏移
    private boolean isLeftOffset = true;

    //当前帧
    private int frame = 0;

    //当前影像ID
    private long imageId = 0;

    //像素间距
    private float pixelSpacing = 0;

    /**
     * 构造函数
     *
     * @param context
     */
    public CustomImageView(Context context) {
        super(context);
        init(context);
    }

    /**
     * 构造函数
     *
     * @param context
     * @param attrs
     */
    public CustomImageView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    /**
     * 构造函数
     *
     * @param context
     * @param attrs
     * @param defStyle
     */
    public CustomImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    /**
     * 设置帧
     *
     * @param currentFrame
     */
    public void setFrame(int currentFrame) {
        this.frame = currentFrame;
    }

    /**
     * 设置影像ID
     *
     * @param imageId
     */
    public void setImageId(long imageId) {
        this.imageId = imageId;
    }

    /**
     * 设置像素间距
     *
     * @param pixelSpacing
     */
    public void setPixelSpacing(double pixelSpacing) {
        float value = (float) pixelSpacing;
        this.pixelSpacing = value;
    }

    /**
     * 是否向左偏移
     *
     * @param leftOffset
     */
    public void setLeftOffset(boolean leftOffset) {
        this.isLeftOffset = leftOffset;
    }

    /**
     * 初始化方法
     */
    private void init(Context context) {
        linePaint.setColor(Color.RED);
        linePaint.setStrokeWidth(2);

        textPaint.setColor(Color.RED);
        textPaint.setStrokeWidth(3);
        textPaint.setTextSize(50);
    }

    /**
     * 计算两个坐标的距离
     *
     * @param startX
     * @param startY
     * @param endX
     * @param endY
     * @return
     */
    private float calculateDistance(float startX, float startY, float endX, float endY) {
        return (float) Math.sqrt(Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2));
    }

    /**
     * 将像素换成mm
     *
     * @param pixels
     * @return
     */
    private float convertPixelsToMm(float pixels) {
        return pixels * this.pixelSpacing;
    }

    /**
     * @param imageMatrix
     */
    public void setImageMatrix(Matrix imageMatrix) {
        this.imageMatrix.set(imageMatrix);
        this.imageMatrix.invert(inverseMatrix);
        reDraw(true);
    }

    /**
     * 绘制
     *
     * @param canvas 画布
     */
    @Override
    protected void onDraw(Canvas canvas) {
        canvas.save();
        canvas.concat(imageMatrix);
        if (lineValues[0] != 0 && lineValues[1] != 0) {
            canvas.drawCircle(lineValues[0], lineValues[1], CURSOR_RADIUS, linePaint);
        }
        if (lineValues[2] != 0 && lineValues[3] != 0) {
            canvas.drawCircle(lineValues[2], lineValues[3], CURSOR_RADIUS, linePaint);
        }
        canvasDraw(canvas, itemList, linePaint, textPaint);
        canvas.restore();
    }

    /**
     * 重新绘制
     *
     * @param flag 是否重新绘制
     */
    public void reDraw(boolean flag) {
        if (flag) {
            //this.canDrawStart = true;
            //this.canDrawEnd = true;
            this.invalidate();
        }
    }

    /**
     * 清除绘制的内容
     *
     * @param currentImageId 影像ID
     * @param currentFrame   当前帧
     */
    public void clearLine(long currentImageId, int currentFrame) {
        this.canDrawStart = this.canDrawEnd = false;
        lineValues[0] = lineValues[1] = lineValues[2] = lineValues[3] = 0;
        itemList.removeIf(p -> p.imageId == currentImageId && p.frame == currentFrame);
        invalidate();
    }

    /**
     * 检测当前帧是否绘制
     * 如果已经绘制 将图片上传到服务端
     *
     * @return
     */
    public boolean hasDraw() {
        if (itemList.stream().anyMatch(p -> p.imageId == this.imageId && p.frame == this.frame)) {
            return true;
        }
        return false;
    }

    /**
     * 事件监听
     *
     * @param event 手指事件.
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (canDrawStart || canDrawEnd) {
            imageMatrix.getValues(matrixValues);
            float xScale = matrixValues[Matrix.MSCALE_X];
            float yScale = matrixValues[Matrix.MSCALE_Y];
            float x = isLeftOffset ? event.getX() - OFFSET_X / xScale : event.getX() + OFFSET_X / xScale;
            float y = isLeftOffset ? event.getY() - OFFSET_Y / yScale : event.getY() - OFFSET_Y / yScale;
            float[] imageValues = new float[]{x, y};
            inverseMatrix.mapPoints(imageValues);
            switch (event.getActionMasked()) {
                case MotionEvent.ACTION_DOWN:
                    if (canDrawStart) {
                        lineValues[0] = x;
                        lineValues[1] = y;
                    } else if (canDrawEnd) {
                        lineValues[2] = x;
                        lineValues[3] = y;
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (canDrawStart) {
                        lineValues[0] = x;
                        lineValues[1] = y;
                    } else if (canDrawEnd) {
                        lineValues[2] = x;
                        lineValues[3] = y;
                    }
                    invalidate();
                    break;
                case MotionEvent.ACTION_UP:
                    if (canDrawStart) {
                        lineValues[0] = x;
                        lineValues[1] = y;
                        this.canDrawStart = false;
                    } else if (canDrawEnd) {
                        lineValues[2] = x;
                        lineValues[3] = y;
                        this.canDrawEnd = false;
                        addLineItem();
                    }
                    invalidate();
                    break;
                default:
                    return false;
            }
            return true;
        } else {
            return super.onTouchEvent(event);
        }
    }

    /**
     * 向结合中添加线条
     */
    private void addLineItem() {
        float distancePixels = calculateDistance(lineValues[0], lineValues[1], lineValues[2], lineValues[3]);
        float distanceMm = convertPixelsToMm(distancePixels);
        itemList.add(new LineItem(this.imageId, frame, new PointF(lineValues[0], lineValues[1]), new PointF(lineValues[2], lineValues[3]), distanceMm));
        lineValues[0] = lineValues[1] = lineValues[2] = lineValues[3] = 0;
    }

    /**
     * 绘制方法
     *
     * @param canvas
     * @param lineItems
     * @param linePaint
     * @param textPaint
     */
    private void canvasDraw(Canvas canvas, List<LineItem> lineItems, Paint linePaint, Paint textPaint) {
        int num = 1;
        List<LineItem> list = lineItems.stream().filter(p -> p.imageId == this.imageId && p.frame == this.frame).collect(Collectors.toList());
        for (LineItem item : list) {
            //canvas.drawCircle(item.start.x, item.start.y, CURSOR_RADIUS, linePaint);
            canvas.drawLine(item.start.x, item.start.y, item.end.x, item.end.y, linePaint);
            //canvas.drawCircle(item.end.x, item.end.y, CURSOR_RADIUS, linePaint);
            String content = String.format("%02d", num) + ": " + String.format("%.2f", item.distance) + "mm";
            canvas.drawText(content, 10, 50 + (num - 1) * 50, textPaint);
            canvas.drawText(String.valueOf(num), item.start.x, item.start.y, textPaint);
            num++;
        }
    }

    class LineItem {
        private long imageId = 0;
        private PointF start;
        private PointF end;
        private int frame = 0;
        private float distance = 0;

        public LineItem(PointF start, PointF end) {
            this.start = start;
            this.end = end;
        }

        public LineItem(long imageId, int frame, PointF start, PointF end, float distance) {
            this.imageId = imageId;
            this.frame = frame;
            this.start = start;
            this.end = end;
            this.distance = distance;
        }
    }
}
